#include "preHeader.h"
#include "OperatingActivityBase.h"
#include "Session/GameServerMgr.h"
#include "Session/DBPSession.h"
#include "Session/DBPHelper.h"
#include "Game/TransMgr.h"
#include "OperatingActivityMgr.h"

OperatingActivityBase::OperatingActivityBase(const OperatingActivity* pProto, ssize_t nSaveData)
: m_pProto(pProto)
, m_nSaveData(nSaveData)
, m_isActEnd(false)
{
}

OperatingActivityBase::~OperatingActivityBase()
{
	for (auto&[playerId, pActData] : m_mapActUserData) {
		delete pActData;
	}
	for (auto&[playerId, pUserData] : m_mapActUserData) {
		delete pUserData;
	}
}

void OperatingActivityBase::InitActivityInstance()
{
	ReloadActivityParams();
	LoadDataFromDB();
}

void OperatingActivityBase::ResetActivityPrototype(const OperatingActivity* pProto)
{
	m_pProto = pProto;
	ReloadActivityParams();
}

void OperatingActivityBase::LoadDataFromDB()
{
	NetPacket rpcReqPck(CDBP_LOAD_ALL_OPERATING_ACTIVITY);
	rpcReqPck << m_pProto->nType << m_pProto->nTimes;
	DBPHelper::RPCBlockInvoke(&sDBPSession, rpcReqPck, [=](INetStream& pck) {
		while (!pck.IsReadableEmpty()) {
			auto pActData = new OperatingActivityData();
			LoadFromINetStream(*pActData, pck);
			if (m_nSaveData > 0) {
				pActData->saveData.resize(m_nSaveData);
			} else if (pActData->saveData.size() < size_t(-m_nSaveData)) {
				pActData->saveData.resize(-m_nSaveData);
			}
			m_mapActData.emplace(pActData->playerId, pActData);
		}
	});
	OnLoadDataFromDB();
}

void OperatingActivityBase::SaveDataToDB(uint32 playerId)
{
	auto itr = m_mapActData.find(playerId);
	if (itr != m_mapActData.end()) {
		auto pActData = itr->second;
		OnPreSaveDataToDB(*pActData);
		NetPacket rpcReqPck(CDBP_SAVE_OPERATING_ACTIVITY);
		SaveToINetStream(*pActData, rpcReqPck);
		sDBPSession.RPCInvoke(rpcReqPck);
	}
}

void OperatingActivityBase::SaveDataToDB(const std::vector<uint32>& playerIds)
{
	MaxNetPacket rpcReqPck(CDBP_SAVE_OPERATING_ACTIVITY);
	for (auto playerId : playerIds) {
		auto itr = m_mapActData.find(playerId);
		if (itr != m_mapActData.end()) {
			auto pActData = itr->second;
			OnPreSaveDataToDB(*pActData);
			SaveToINetStream(*pActData, rpcReqPck);
		}
	}
	if (!rpcReqPck.IsBufferEmpty()) {
		sDBPSession.RPCInvoke(rpcReqPck);
	}
}

void OperatingActivityBase::BuildActivityDetailPacket(NetPacket& pck, const OperatingPlayerInfo& info)
{
	pck << m_pProto->strDesc;
	pck << m_pProto->nPlayReqVipLevel;
	pck << m_pProto->nPlayReqLevel;
	pck << m_pProto->nPlayStartTime;
	pck << m_pProto->nPlayEndTime;
	pck << m_pProto->strClientParams;
	BuildActivityParamsPacket(pck, info);
	auto pActData = GetActivityData(info.playerId);
	pck << bool(pActData != NULL);
	if (pActData != NULL) {
		pck << (u16)pActData->saveData.size();
		for (auto saveData : pActData->saveData) {
			pck << saveData;
		}
		pck << pActData->userData;
	}
}

void OperatingActivityBase::BuildActivityIntroPacket(NetPacket& pck, const OperatingPlayerInfo& info)
{
	pck << m_pProto->nType;
	pck << m_pProto->nUIType;
	pck << m_pProto->strName;
	pck << m_pProto->nShowEndTime;
	pck << m_pProto->nDailyStartTime;
	pck << m_pProto->nDailyEndTime;
}

void OperatingActivityBase::BroadcastActivityDataDirty() const
{
	NetPacket pck(SMSG_OPERATING_DETAIL_DIRTY);
	pck << GetOperatingUniqueKey(*m_pProto);
	sTransMgr.BroadcastPacket2AllClientSafe(pck);
}

OperatingActivityData* OperatingActivityBase::GetActivityData(uint32 playerId) const
{
	auto itr = m_mapActData.find(playerId);
	return itr != m_mapActData.end() ? itr->second : NULL;
}

OperatingActivityData* OperatingActivityBase::CreateAndGetActivityData(uint32 playerId)
{
	auto pActData = GetActivityData(playerId);
	if (pActData == NULL) {
		pActData = new OperatingActivityData();
		InitActivityData(playerId, *pActData);
		m_mapActData.emplace(playerId, pActData);
	}
	return pActData;
}

void OperatingActivityBase::InitActivityData(uint32 playerId, OperatingActivityData& actData) const
{
	actData.playerId = playerId;
	actData.actType = m_pProto->nType;
	actData.actTimes = m_pProto->nTimes;
	actData.saveData.resize(std::abs(m_nSaveData));
}

void OperatingActivityBase::ClearActivitySaveData(OperatingActivityData& actData)
{
	std::fill(actData.saveData.begin(), actData.saveData.end(), 0);
}

OperatingActivityUserDataBase* OperatingActivityBase::GetActivityUserData(uint32 playerId) const
{
	auto itr = m_mapActUserData.find(playerId);
	return itr != m_mapActUserData.end() ? itr->second : NULL;
}

OperatingActivityUserDataBase* OperatingActivityBase::CreateAndGetActivityUserData(const OperatingActivityData& actData)
{
	auto pUserData = GetActivityUserData(actData.playerId);
	if (pUserData == NULL) {
		pUserData = CreateActivityUserData(actData);
		if (pUserData != NULL) {
			m_mapActUserData.emplace(actData.playerId, pUserData);
		}
	}
	return pUserData;
}

void OperatingActivityBase::SendRewardMail(
	uint32 playerId, const std::vector<FItemInfo>& rewardItems,
	uint32 subjectStrId, uint32 bodyStrId,
	const std::string_view& subjectArgs, const std::string_view& bodyArgs,
	size_t times)
{
	NetPacket pack(SGX_SEND_OPERATING_REWARD_MAIL);
	pack << playerId << subjectStrId << bodyStrId << subjectArgs << bodyArgs;
	pack << (u32)times << (u16)rewardItems.size();
	for (auto& rewardItem : rewardItems) {
		SaveToINetStream(rewardItem, pack);
	}
	sGameServerMgr.SendPacket2GS(pack);
}

GErrorCode OperatingActivityBase::GetRewardItems(
	const OperatingPlayerInfo& info, const std::vector<FItemInfo>& rewardItems,
	bool isAllowMail, size_t times, const std::function<bool()>& errResp)
{
	NetPacket rpcReqPck(G2M_GET_OPERATING_REWARD_ITEMS);
	rpcReqPck << m_pProto->nType << m_pProto->nTimes
		<< isAllowMail << (u32)times << (u16)rewardItems.size();
	for (auto& rewardItem : rewardItems) {
		SaveToINetStream(rewardItem, rpcReqPck);
	}
	auto pActMgr = &sOperatingActivityMgr;
	auto errCode = sGameServerMgr.RPCInvoke2Player(
		info.playerId, rpcReqPck, [=](INetStream& pck, int32 err, bool) {
			bool isDataDirty = false;
			_defer_r(if (isDataDirty) { SaveDataToDB(info.playerId); })
			if (err != RPCErrorNone) {
				WLOG("Operating activity get reward items failed, %u.", err);
				isDataDirty = errResp();
				return;
			}
			int32 errCode;
			pck >> errCode;
			auto actUniqueKey = GetOperatingUniqueKey(*m_pProto);
			NetPacket respPck(SMSG_OPERATING_GET_REWARD_RESP_CONTINUE);
			respPck << actUniqueKey << errCode;
			sTransMgr.SendPacket2ClientSafe(info.playerId, respPck);
			if (errCode != CommonSuccess) {
				isDataDirty = errResp();
				return;
			}
			pActMgr->BuildActivityDetailPacket(info, actUniqueKey);
		}, pActMgr, DEF_S2S_RPC_TIMEOUT);
	if (errCode != RPCErrorNone) {
		WLOG("Operating activity get reward items failed, %u.", errCode);
		return CommonInternalError;
	}
	return CommonSuccess;
}
